﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Xml;
using Assist;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using YArchitech.Controls;
using YArchitech.LIB;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKRevitBase.WinForm;
using YJKRevitFamilyDataBase;
using YJKOpeningCommon.DataEnum;
using YJKOpeningDesignInput.ConfigForm;
using YJKRevitKernel.ElementSearchUtility.LinkDocumentSuite;
using YJKRevitView;

namespace YJKOpeningDesignInput.Cmd
{
	[Transaction(TransactionMode.Manual)]
	[Regeneration(RegenerationOption.Manual)]
	public class CmdCasingPipeAdd : IExternalCommand
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result Execute(ExternalCommandData cmdData, ref string messages, ElementSet elements)
		{
			try
			{
				this.m_uiDoc = cmdData.Application.ActiveUIDocument;
				this.m_doc = this.m_uiDoc.Document;
				CmdViewType types = (CmdViewType)3;
				if (SwitchView.SetUsableView(types, cmdData) != Autodesk.Revit.UI.Result.Succeeded)
				{
					return Autodesk.Revit.UI.Result.Failed;
				}
				this.m_xmlDoc = new XmlDocument();
				this.m_xmlDoc.Load(Product.DataLocation + "\\DrivepipeData.xml");
                WindowHandle windowHandle = new WindowHandle(Process.GetCurrentProcess().MainWindowHandle);
				CasingPipeAddForm casingPipeAddForm = new CasingPipeAddForm(windowHandle);
				casingPipeAddForm.Show(windowHandle);
				int wMsg = 7;
				CmdCasingPipeAdd.SendMessage(windowHandle.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
				this.GetDocCasingPipe();
				List<Pipe> lstPipe = new List<Pipe>();
				for (;;)
				{
					if (this.SelectPipeOper((short)casingPipeAddForm.m_nSelPipeType, ref lstPipe))
					{
						this.m_strPipeDiaType = casingPipeAddForm.m_strPipeDiaType;
						this.AddCasingPipeOper(casingPipeAddForm.m_nDrivepipeType, lstPipe);
					}
					else
					{
						if (!casingPipeAddForm.m_bSelPipeTypeChange)
						{
							break;
						}
						casingPipeAddForm.m_bSelPipeTypeChange = false;
					}
				}
				casingPipeAddForm.Close();
			}
			catch
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private string GetDrivepipeDimName(string strFamilyName)
		{
			if (strFamilyName.Contains("穿墙套管"))
			{
				return "穿墙套管";
			}
			if (strFamilyName.Contains("防水套管"))
			{
				return "防水套管";
			}
			if (strFamilyName.Contains("密闭套管"))
			{
				return "密闭套管";
			}
			return "穿墙套管";
		}

		private string GetCasingDimMark(string sFamilyName, int nPipeDia)
		{
			string str = string.Format("管径{0}", nPipeDia);
			XmlNode xmlNode = this.m_xmlDoc.SelectSingleNode("Root/" + sFamilyName + "/" + str);
			if (xmlNode == null)
			{
				return null;
			}
			XmlAttribute xmlAttribute = xmlNode.Attributes[this.m_strPipeDiaType];
			if (xmlAttribute == null || xmlAttribute.Value == null)
			{
				return null;
			}
			if (sFamilyName == "穿墙套管")
			{
				return "φ" + xmlAttribute.Value;
			}
			return string.Concat(new string[]
			{
				this.GetDrivepipeDimName(sFamilyName),
				" ",
				this.m_strPipeDiaType,
				" ",
				xmlAttribute.Value
			});
		}

		private void AddCasingPipeOper(ECasingPipeType eCasingPipeType, List<Pipe> lstPipe)
		{
			string casingPipeFamilyName = this.GetCasingPipeFamilyName(eCasingPipeType);
			this.m_CasingPipeSymbol = CmdCasingPipeAdd.LoadOpeningFamily(this.m_doc, casingPipeFamilyName);
			if (this.m_CasingPipeSymbol == null)
			{
				return;
			}
			int num = 0;
			foreach (Pipe pipe in lstPipe)
			{
				int num2 = (int)AssistFunc.feetToMM(pipe.Diameter);
				string casingDimMark = this.GetCasingDimMark(casingPipeFamilyName, num2);
				if (casingDimMark == null)
				{
					if (lstPipe.Count == 1)
					{
						string str = string.Format("管径{0}", num2);
						YJKMessageBox.Show(casingPipeFamilyName + " 没有" + str + " 的数据。");
					}
					else
					{
						num++;
					}
				}
				else
				{
					this.AddCasingpipeForPipe(pipe, casingDimMark);
				}
			}
			if (num > 0)
			{
				YJKMessageBox.Show(string.Format("有{0}根水管查询不到套管数据，不能加套管。", num));
			}
		}

		public static XYZ FindWallVector(Wall wall)
		{
			LocationCurve locationCurve = wall.Location as LocationCurve;
			return locationCurve.Curve.GetEndPoint(1) - locationCurve.Curve.GetEndPoint(0);
		}

		private void AddCasingpipeForPipe(Pipe pipe, string sMark)
		{
			BoundingBoxXYZ pipeBox3D = pipe.get_BoundingBox(this.m_doc.ActiveView);
			List<Wall> wallByPipeBoundingBox = this.GetWallByPipeBoundingBox(pipeBox3D);
			XYZ direction = CmdCasingPipeAdd.FindPipeLine(pipe).Direction;
			double dCasingPipeAngle = XYZ.BasisX.AngleOnPlaneTo(direction, XYZ.BasisZ);
			this.RemoveCasingPipeByPipeIdOper(pipe.UniqueId);
			foreach (Wall wall in wallByPipeBoundingBox)
			{
				if (!((wall.Location as LocationCurve).Curve.GetType() == typeof(Arc)) && Math.Abs(CmdCasingPipeAdd.FindWallVector(wall).AngleTo(direction) - Math.PI*.5) <= 0.0001)
				{
					List<XYZ> pipeIntersect2WallPos = CmdCasingPipeAdd.GetPipeIntersect2WallPos(pipe, wall);
					if (pipeIntersect2WallPos.Count != 0)
					{
						double dCasingPipeDia = AssistFunc.mmToFeet(100.0);
						double width = wall.WallType.Width;
						foreach (XYZ ptPos in pipeIntersect2WallPos)
						{
							Element element = this.InsertCasingPipe(ptPos, dCasingPipeDia, width, dCasingPipeAngle, sMark);
							if (element != null)
							{
								this.WriteXData2CasingPipe(element, pipe.UniqueId);
							}
						}
					}
				}
			}
		}

		private string GetCasingPipeFamilyName(ECasingPipeType eCasingPipeType)
		{
			return StrCasingPipeType.m_strCasingPipeType[(int)eCasingPipeType];
		}

		private void GetDocCasingPipe()
		{
			try
			{
				this.m_lstDocCasingPipe = new List<FamilyInstance>();
				foreach (Element element in YJKElementFilter.GetElementByClass(typeof(FamilyInstance), this.m_doc))
				{
					string text = this.ReadXDataFromCasingPipe(element);
					if (!(text == string.Empty))
					{
						bool element2 = this.m_doc.GetElement(text) != null;
						FamilyInstance familyInstance = element as FamilyInstance;
						if (element2 && familyInstance != null)
						{
							this.m_lstDocCasingPipe.Add(familyInstance);
						}
					}
				}
			}
			catch (Exception ex)
			{
				YJKMessageBox.Show(ex.Message);
			}
		}

		private static Curve GetElemLocationCurve(Element elem)
		{
			if (elem == null)
			{
				return null;
			}
			LocationCurve locationCurve = elem.Location as LocationCurve;
			if (locationCurve == null)
			{
				return null;
			}
			return locationCurve.Curve;
		}

		private static bool GetElemLocationCurve(Element elem, ref XYZ ptStart, ref XYZ ptEnd)
		{
			Curve elemLocationCurve = CmdCasingPipeAdd.GetElemLocationCurve(elem);
			if (elemLocationCurve != null)
			{
				ptStart = elemLocationCurve.GetEndPoint(0);
				ptEnd = elemLocationCurve.GetEndPoint(1);
				return true;
			}
			return false;
		}

		public static List<XYZ> GetPipeIntersect2WallPos(Pipe pipe, Wall wall)
		{
			Line line = CmdCasingPipeAdd.FindPipeLine(pipe);
			List<XYZ> list = new List<XYZ>();
			try
			{
				XYZ endPoint = line.GetEndPoint(0);
				XYZ endPoint2 = line.GetEndPoint(1);
				XYZ zero = XYZ.Zero;
				XYZ zero2 = XYZ.Zero;
				if (!CmdCasingPipeAdd.GetElemLocationCurve(wall, ref zero, ref zero2))
				{
					return null;
				}
				double z = zero.Z;
				XYZ xyz = new XYZ(endPoint.X, endPoint.Y, z);
				XYZ xyz2 = new XYZ(endPoint2.X, endPoint2.Y, z);
				Curve curve = Line.CreateBound(xyz, xyz2);
				IntersectionResultArray intersectionResultArray = null;
				Curve elemLocationCurve = CmdCasingPipeAdd.GetElemLocationCurve(wall);
                if ((int)curve.Intersect(elemLocationCurve, out intersectionResultArray) != 8)
				{
					return null;
				}
				for (int i = 0; i < intersectionResultArray.Size; i++)
				{
					XYZ xyzpoint = intersectionResultArray.get_Item(i).XYZPoint;
					Curve curve2 = Line.CreateUnbound(xyzpoint, XYZ.BasisZ);
					IntersectionResultArray intersectionResultArray2 = null;
                    if ((int)curve2.Intersect(line, out intersectionResultArray2) == 8 && intersectionResultArray2.Size > 0)
					{
						xyzpoint = intersectionResultArray2.get_Item(0).XYZPoint;
						list.Add(xyzpoint);
					}
				}
			}
			catch
			{
			}
			return list;
		}

		public static Line FindPipeLine(Pipe pipe)
		{
			LocationCurve locationCurve = pipe.Location as LocationCurve;
			return YJKLineEx.YJKGetBound(locationCurve.Curve.GetEndPoint(0), locationCurve.Curve.GetEndPoint(1));
		}

		private List<Wall> GetWallByPipeBoundingBox(BoundingBoxXYZ pipeBox3D)
		{
			List<Wall> list = new List<Wall>();
			try
			{
				FilteredElementCollectorLinkDocument filteredElementCollectorLinkDocument = new FilteredElementCollectorLinkDocument(this.m_doc);
				BoundingBoxIntersectsFilter input = new BoundingBoxIntersectsFilter(new Outline(pipeBox3D.Min, pipeBox3D.Max));
				filteredElementCollectorLinkDocument.OfCalss(typeof(Wall));
				filteredElementCollectorLinkDocument.AddViewLimit(input);
				foreach (BaseLinkDocumentResultBean baseLinkDocumentResultBean in filteredElementCollectorLinkDocument.ToBeans())
				{
					Wall wall = baseLinkDocumentResultBean.UseElement as Wall;
					if (wall != null && !wall.IsStackedWallMember)
					{
						list.Add(wall);
					}
				}
			}
			catch (Exception ex)
			{
				YJKMessageBox.Show(ex.Message);
			}
			return list;
		}

		private Element InsertCasingPipe(XYZ ptPos, double dCasingPipeDia, double dCasingPipeLen, double dCasingPipeAngle, string strDimItem)
		{
			Transaction transaction = new Transaction(this.m_doc, "InsertFamilySymbol");
			transaction.Start();
			try
			{
				UnifiedModified.ActivateFamilySymbol(this.m_CasingPipeSymbol);
				FamilyInstance familyInstance = this.m_doc.Create.NewFamilyInstance(ptPos, this.m_CasingPipeSymbol, this.m_doc.ActiveView);
				this.m_doc.Regenerate();
				familyInstance.GetParameter("墙厚度").Set(dCasingPipeLen);
				familyInstance.GetParameter("管宽度").Set(dCasingPipeDia);
				familyInstance.GetParameter("总宽度").Set(dCasingPipeDia + 0.5);
				Line line = YJKLineEx.YJKGetUnBound(ptPos, XYZ.BasisZ);
				ElementTransformUtils.RotateElement(this.m_doc, familyInstance.Id, line, dCasingPipeAngle);
				this.WriteSharedParam2CasingPipe(familyInstance, AssistFunc.feetToMM(ptPos.Z) / 1000.0, strDimItem);
				this.m_lstDocCasingPipe.Add(familyInstance);
				transaction.Commit();
				return familyInstance;
			}
			catch
			{
				transaction.RollBack();
			}
			return null;
		}

		private static FamilySymbol LoadOpeningFamily(Autodesk.Revit.DB.Document doc, string strFamilyName)
		{
			FamilySymbol familySymbol = YJKRevitTools.GetFamilySymbol(strFamilyName, doc);
			if (familySymbol != null)
			{
				return familySymbol;
			}
			string text = Path.Combine(FamilyLibDatabase.GetDefFamilyLibPath(), string.Concat(new string[]
			{
				"Family\\",
				RevitVersion.Version,
				"\\Opening\\",
				strFamilyName,
				".rfa"
			}));
			Family family = null;
			try
			{
				Transaction transaction = new Transaction(doc, "CreateOpening");
				transaction.Start();
				doc.LoadFamily(text, out family);
				transaction.Commit();
			}
			catch (Exception ex)
			{
				YJKMessageBox.Show(ex.Message);
				return null;
			}
			return family.GetSymbols().FirstOrDefault<FamilySymbol>();
		}

		private string ReadXDataFromCasingPipe(Element elemCasingPipe)
		{
			string result = string.Empty;
			try
			{
				Guid guid = new Guid(CmdCasingPipeAdd.m_strXDataGuid);
				Schema schema = Schema.Lookup(guid);
				if (schema != null)
				{
					Entity entity = elemCasingPipe.GetEntity(schema);
					if (entity != null && entity.SchemaGUID == guid)
					{
						Field field = schema.GetField("AttachPipeGUId");
						result = entity.Get<string>(field);
					}
				}
			}
			catch
			{
			}
			return result;
		}

		private bool WriteXData2CasingPipe(Element elemCasingPipe, string strPipeUniqueId)
		{
			try
			{
				Transaction transaction = new Transaction(elemCasingPipe.Document, "WriteXData");
				transaction.Start();
				Guid guid = new Guid(CmdCasingPipeAdd.m_strXDataGuid);
				Schema schema = Schema.Lookup(guid);
				if (schema == null)
				{
					SchemaBuilder schemaBuilder = new SchemaBuilder(guid);
					schemaBuilder.SetSchemaName("CasingPipeXData");
					schemaBuilder.AddSimpleField("AttachPipeGUId", typeof(string));
					schema = schemaBuilder.Finish();
				}
				Entity entity = new Entity(schema);
				Field field = schema.GetField("AttachPipeGUId");
				entity.Set<string>(field, strPipeUniqueId);
				elemCasingPipe.SetEntity(entity);
				transaction.Commit();
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private void RemoveCasingPipeByPipeIdOper(string strPipeUniqueId)
		{
			Transaction transaction = new Transaction(this.m_doc, "DeleteInstance");
			try
			{
				transaction.Start();
				for (int i = 0; i < this.m_lstDocCasingPipe.Count; i++)
				{
					FamilyInstance familyInstance = this.m_lstDocCasingPipe[i];
					if (this.ReadXDataFromCasingPipe(familyInstance) == strPipeUniqueId)
					{
						this.m_doc.Delete(familyInstance.Id);
						this.m_lstDocCasingPipe.Remove(familyInstance);
						i--;
					}
				}
				transaction.Commit();
			}
			catch
			{
			}
		}

		private bool SelectPipeOper(short nSelType, ref List<Pipe> lstSelPipe)
		{
			try
			{
				lstSelPipe.Clear();
				PipeFilter pipeFilter = new PipeFilter();
				if (nSelType == 0)
				{
					Reference reference = this.m_uiDoc.Selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, pipeFilter, "请选择一条垂直穿墙水平水管");
					Element element = this.m_uiDoc.Document.GetElement(reference);
					lstSelPipe.Add(element as Pipe);
				}
				else
				{
					foreach (Element element2 in this.m_uiDoc.Selection.PickElementsByRectangle(pipeFilter, "请框选垂直穿墙水平水管"))
					{
						lstSelPipe.Add(element2 as Pipe);
					}
				}
			}
			catch
			{
				return false;
			}
			return true;
		}

		private void WriteSharedParam2CasingPipe(FamilyInstance fiCasingPipe, double dElev, string strDimItem)
		{
			try
			{
                BuiltInCategory integerValue = (BuiltInCategory)fiCasingPipe.Category.Id.IntegerValue;
				Dictionary<string, ParameterType> dictionary = new Dictionary<string, ParameterType>();
				if (fiCasingPipe.GetParameter("标注标高") == null)
				{
                    dictionary.Add("标注标高", (ParameterType)1);
				}
				if (fiCasingPipe.GetParameter("标注内容") == null)
				{
                    dictionary.Add("标注内容", (ParameterType)1);
				}
				if (dictionary.Count > 0)
				{
					SharedParameter.InsertSharedParameter(this.m_doc, integerValue, "套管信息", dictionary, false, true);
				}
				fiCasingPipe.GetParameter("标注标高").Set(dElev.ToString("f3"));
				fiCasingPipe.GetParameter("标注内容").Set(strDimItem);
				this.m_doc.Regenerate();
			}
			catch
			{
			}
		}

        public WindowHandle _hWndRevit;

		private Document m_doc;

		private List<FamilyInstance> m_lstDocCasingPipe;

		private UIDocument m_uiDoc;

		private XmlDocument m_xmlDoc;

		private FamilySymbol m_CasingPipeSymbol;

		private string m_strPipeDiaType;

		private static string m_strXDataGuid = "545EDF2F-ABFE-4EBB-934C-035346568733";
	}
}
